package com.harmontronics.hanma.paas.paas.domain.app.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.harmontronics.hanma.paas.paas.common.PageBase;
import com.harmontronics.hanma.paas.paas.consts.DbConstants;
import com.harmontronics.hanma.paas.paas.domain.app.entity.HmPage;
import com.harmontronics.hanma.paas.paas.domain.app.entity.valueobject.Fields;
import com.harmontronics.hanma.paas.paas.domain.app.entity.valueobject.I18nKeyEnum;
import com.harmontronics.hanma.paas.paas.domain.app.entity.valueobject.PageTypeEnum;
import com.harmontronics.hanma.paas.paas.domain.app.repository.persistence.HmModelRepository;
import com.harmontronics.hanma.paas.paas.domain.app.repository.persistence.HmPageRepository;
import com.harmontronics.hanma.paas.paas.domain.app.repository.po.HmModelPO;
import com.harmontronics.hanma.paas.paas.domain.app.repository.po.HmPagePO;
import com.harmontronics.hanma.paas.paas.exception.ErrorKeyException;
import com.harmontronics.hanma.paas.paas.utils.EscapeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author ldb
 */
@Service("hmPageService")
@DS("#header.App-Unique")
public class HmPageService {

    @Autowired
    private HmPageRepository hmPageRepository;

    @Autowired
    private HmModelRepository hmModelRepository;


    public HmPage findById(Long id, Boolean includeJson) {
        HmPagePO po = hmPageRepository.getById(id);
        required(po);
        if (includeJson == null || !includeJson) {
            po.setJson(null);
        }
        return BeanUtil.toBean(po, HmPage.class);
    }

    public List<HmPage> findByIds(List<Long> ids, Boolean includeJson) {
        if (CollectionUtils.isEmpty(ids)) {
            return new ArrayList<>();
        }
        List<HmPagePO> pos = hmPageRepository.listByIds(ids);

        if (includeJson == null || !includeJson) {
            pos.forEach(e -> e.setJson(null));
        }
        return Convert.toList(HmPage.class, pos);
    }

    public Long save(HmPage hmPage) {
        validField(null, Fields.NAME, hmPage.getName(), hmPage.getType());
        HmPagePO po = BeanUtil.toBean(hmPage, HmPagePO.class);
        String key = getKey();
        po.setKey(key);
        hmPageRepository.save(po);
        return po.getId();
    }

    private String getKey() {
        String key = RandomUtil.randomString(7);
        if (hmPageRepository.keyExists(key)) {
            return getKey();
        }
        return key;
    }

    public void update(HmPage hmPage) {

        HmPagePO po = hmPageRepository.getById(hmPage.getId());
        validField(hmPage.getId(), Fields.NAME, hmPage.getName(), po.getType());
        //只能修改名称和描述信息
        po.setName(hmPage.getName());
        po.setDescription(hmPage.getDescription());
        hmPageRepository.updateById(po);
    }


    private void required(HmPagePO hmPagePO) {
        if (hmPagePO == null) {
            throw new ErrorKeyException(I18nKeyEnum.PAGE_NOT_FOUND);
        }
    }

    public void remove(List<Long> ids) {
        hmPageRepository.removeByIds(ids);
    }

    public List<HmPage> getList(Long modelId, PageTypeEnum type, Boolean filterNonJson) {
        List<HmPagePO> pos = type == null ? hmPageRepository.findByModelId(modelId) : hmPageRepository.findByModelIdAndType(modelId, type);
        if (filterNonJson != null && filterNonJson) {
            pos = pos.stream().filter(e -> !StringUtils.isEmpty(e.getJson())).collect(Collectors.toList());
        }
        return Convert.toList(HmPage.class, pos);
    }

    public PageBase<HmPage> getList(PageTypeEnum type, String name, int pageNo, int pageSize) {
        Page<HmPagePO> page = new Page<>(pageNo, pageSize);
        QueryWrapper<HmPagePO> queryWrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(name)) {
            queryWrapper.like(Fields.NAME, EscapeUtil.escapeChar(name));
        }
        if (type != null) {
            queryWrapper.eq(Fields.TYPE_DB, type);
        }
        queryWrapper.orderByDesc(DbConstants.CREATE_DATE);
        IPage<HmPagePO> resultPage =
                hmPageRepository.selectPage(queryWrapper, page);
        //json会比较大 列表页不需要
        resultPage.getRecords().forEach(e -> e.setJson(null));

        PageBase<HmPage> finalPage = PageBase.from(resultPage, HmPage.class);
        setModelInfo(finalPage.getData());
        return finalPage;
    }

    private void setModelInfo(List<HmPage> pages) {
        if (pages.isEmpty()) {
            return;
        }
        List<Long> modelIds = pages.stream().map(HmPage::getModelId).collect(Collectors.toList());
        List<HmModelPO> modelPOS = hmModelRepository.listByIds(modelIds);
        Map<Long, HmModelPO> modelPOMap = modelPOS.stream().collect(Collectors.toMap(HmModelPO::getId, Function.identity()));
        for (HmPage hmPage : pages) {
            HmModelPO hmModelPO = modelPOMap.get(hmPage.getModelId());
            if (hmModelPO != null) {
                hmPage.setModelCode(hmModelPO.getCode());
                hmPage.setModelName(hmModelPO.getName());
            }
        }
    }

    public void validField(Long id, String key, String value, PageTypeEnum pageTypeEnum) {
        if (Fields.NAME.equals(key)) {
            HmPagePO po = hmPageRepository.findByNameAndType(value, pageTypeEnum);
            if (po == null) {
                return;
            }
            if (id == null) {
                throw new ErrorKeyException(I18nKeyEnum.FORM_NAME_EXISTS);
            }
            if (po.getId().longValue() != id.longValue()) {
                throw new ErrorKeyException(I18nKeyEnum.FORM_NAME_EXISTS);
            }

        }
    }

    public void updateJson(Long id, String json) {
        HmPagePO hmPagePO = hmPageRepository.getById(id);
        required(hmPagePO);
        hmPagePO.setJson(json);
        hmPageRepository.updateById(hmPagePO);
    }

    public Long copy(Long sourceId, String name, String description) {
        HmPagePO hmPagePO = hmPageRepository.getById(sourceId);
        required(hmPagePO);
        HmPagePO copyPo = BeanUtil.toBean(hmPagePO, HmPagePO.class);
        copyPo.setId(null);
        copyPo.setKey(getKey());
        copyPo.setName(name);
        copyPo.setDescription(description);
        copyPo.setCreateBy(null);
        copyPo.setCreateDate(null);
        copyPo.setModifyBy(null);
        copyPo.setModifyDate(null);
        hmPageRepository.save(copyPo);
        return copyPo.getId();
    }

    public HmPage findByKey(String key, Boolean includeJson) {
        HmPagePO po = hmPageRepository.findByKey(key);
        required(po);
        if (includeJson == null || !includeJson) {
            po.setJson(null);
        }
        return BeanUtil.toBean(po, HmPage.class);
    }

    public List<HmPage> getListAll(Boolean filterNonJson) {
        List<HmPagePO> pos =  hmPageRepository.list() ;
        if (filterNonJson != null && filterNonJson) {
            pos = pos.stream().filter(e -> !StringUtils.isEmpty(e.getJson())).collect(Collectors.toList());
        }
        return Convert.toList(HmPage.class, pos);
    }
}